package com.ideal.ete.collector.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.ideal.ete.collector.ppLook.PpTools;
import com.ideal.ete.collector.ppLook.ServiceRelation;
import com.ideal.ete.collector.ppLook.ServicesBean;
import com.ideal.ete.collector.ppLook.TreeNode;
import com.ideal.ete.collector.service.MyService;

import org.springframework.beans.factory.annotation.Value;

/**
 * 
 * 功能说明: 提供rest接口方法
 *
 * @author Leo
 * 
 * @Date 2017年9月28日 上午10:12:51
 *
 *
 *       版本号 | 作者 | 修改时间 | 修改内容
 *
 */
@RestController
@RequestMapping("/my")
public class PpController {

	@Value("${url.ideal-pp-web:http://10.145.196.107:38080}")
	private String url;

	@Autowired
	public MyService aserviceImpl;

	@RequestMapping("/hello/{name}")
	public String hello(@PathVariable String name) {
		return "Hello, " + name;
	}

	private final SimpleDateFormat sdf = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss S");

	private RestTemplate rs = new RestTemplate();

	@RequestMapping(value = "/applications", method = RequestMethod.GET)
	public String getApplicationGroup() {
		Object model = rs.getForObject(url + "/applications.pinpoint",
				Object.class);
		String str = JSON.toJSONString(model);
		System.out.println(JSON.toJSONString(model));
		return str;
	}

	// 根据appName、时间区间和条数查询调用链list
	@RequestMapping(value = "/transactionListForConditions", method = RequestMethod.GET)
	public String transactionListForConditions(
			@RequestParam("applicationName") String applicationName,
			@RequestParam(value = "startTimestamp", required = false, defaultValue = "0") long startTimestamp,
			@RequestParam(value = "endTimestamp", required = false, defaultValue = "0") long endTimestamp,
			@RequestParam(value = "limit", required = false, defaultValue = "100") int limit) {
		String s = url
				+ "/transactionListForConditions.pinpoint?applicationName="
				+ applicationName + "&startTimestamp=" + startTimestamp
				+ "&endTimestamp=" + endTimestamp + "&limit=" + limit;
		System.out.println(s);
		Object model = rs.getForObject(url
				+ "/transactionListForConditions.pinpoint?applicationName="
				+ applicationName + "&startTimestamp=" + startTimestamp
				+ "&endTimestamp=" + endTimestamp + "&limit=" + limit,
				Object.class);
		String str = JSON.toJSONString(model);
		System.out.println(str);
		return str;
	}

	// 根据appName查询其所有的rpc
	@RequestMapping(value = "/rpcsForApp", method = RequestMethod.GET)
	public String rpcsForApp(
			@RequestParam("applicationName") String applicationName) {
		String s = url
				+ "/transactionListForConditions.pinpoint?applicationName="
				+ applicationName + "&startTimestamp=0" + "&endTimestamp="
				+ System.currentTimeMillis();
		System.out.println(s);
		List<Map> list = rs.getForObject(s, ArrayList.class);
		Set<String> rpcSet = new HashSet<>();
		for (Map map : list) {
			rpcSet.add(String.valueOf(map.get("rpc")));
		}
		return JSON.toJSONString(rpcSet);
	}

	// 根据appName、rpc、时间区间查询调用链list
	@RequestMapping(value = "/transactionListForRpc", method = RequestMethod.GET)
	public String transactionListForRpc(
			@RequestParam("applicationName") String applicationName,
			@RequestParam("rpc") String rpc,
			@RequestParam(value = "startTimestamp", required = false, defaultValue = "0") long startTimestamp,
			@RequestParam(value = "endTimestamp", required = false, defaultValue = "0") long endTimestamp) {
		String s = url
				+ "/transactionListForConditions.pinpoint?applicationName="
				+ applicationName + "&startTimestamp=" + startTimestamp
				+ "&endTimestamp=" + endTimestamp;
		System.out.println(s);
		List<Map> list = rs.getForObject(s, ArrayList.class);
		List<Map> filterList = new ArrayList<>();
		for (Map map : list) {
			if (String.valueOf(map.get("rpc")).equals(rpc)) {
				filterList.add(map);
			}
		}
		return JSON.toJSONString(filterList);
	}

	// 根据appName、rpc、时间区间查询其服务链
	@RequestMapping(value = "/servicesForConditions", method = RequestMethod.GET)
	public String servicesForConditions(
			@RequestParam("applicationName") String applicationName,
			@RequestParam("rpc") String rpc,
			@RequestParam(value = "startTimestamp", required = false, defaultValue = "0") long startTimestamp,
			@RequestParam(value = "endTimestamp", required = false, defaultValue = "0") long endTimestamp) {
		String s = url
				+ "/transactionListForConditions.pinpoint?applicationName="
				+ applicationName + "&startTimestamp=" + startTimestamp
				+ "&endTimestamp=" + endTimestamp;
		System.out.println(s);
		String tempK;
		List<Map> list = rs.getForObject(s, ArrayList.class);
		Map spanTrMap;
		ServicesBean sb;
		List<ServicesBean> sbs;
		Map<String, Long> relaMap = new HashMap<>();
		for (Map map : list) {
			if (String.valueOf(map.get("rpc")).equals(rpc)) {
				spanTrMap = rs
						.getForObject(
								url
										+ "/transactionInfo.pinpoint?traceId="
										+ PpTools
												.getTransactionId((Map<String, String>) map
														.get("transactionId"))
										+ "&agentId="
										+ String.valueOf(map.get("agentId"))
										+ "&spanId="
										+ String.valueOf(map.get("spanId")),
								Map.class);
				sbs = new ArrayList<>();
				for (List strs : (List<List>) spanTrMap.get("callStack")) {
					if (strs.get(10).equals("Tomcat Servlet Process")) {
						sb = new ServicesBean();
						sb.setTgtApp(strs.get(4).toString());
						sb.setTgtRpc(strs.get(4) + ":" + strs.get(11));
						if (sbs.isEmpty()) {
							sb.setSrcApp("USER");
							sb.setSrcRpc("USER");
						} else {
							sb.setSrcApp(sbs.get(sbs.size() - 1).getTgtApp());
							sb.setSrcRpc(sbs.get(sbs.size() - 1).getTgtRpc());
						}
						for (ServicesBean tsb : sbs) {
							if (tsb.getTgtApp().equals(sb.getTgtApp())) {
								sb.setSrcApp(tsb.getSrcApp());
								sb.setSrcRpc(tsb.getSrcRpc());
								break;
							}
						}
						sbs.add(sbs.size(), sb);
						tempK = sb.getServicesRelation();
						if (relaMap.containsKey(tempK)) {
							relaMap.put(tempK, relaMap.get(tempK) + 1L);
						} else {
							relaMap.put(tempK, 1L);
						}
					}
				}
			}
		}
		List<ServiceRelation> resultList = new ArrayList<>();
		String[] temps;
		ServiceRelation sr;
		for (Map.Entry<String, Long> entry : relaMap.entrySet()) {
			System.out.println(entry.getKey());
			temps = entry.getKey().split("\\|\\|");
			sr = new ServiceRelation(temps[0], temps[1], entry.getValue()
					.toString());
			resultList.add(sr);
		}
		return JSON.toJSONString(resultList);
	}

	// 根据traceId、、时间区间查询其服务链
	@RequestMapping(value = "/transactionLink", method = RequestMethod.GET)
	public String transactionLink(
			@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId) {
		ServicesBean sb;
		String tempK;
		Map<String, Long> relaMap = new HashMap<>();
		List<ServicesBean> sbs;
		String s = url + "/transactionInfo.pinpoint?traceId=" + traceIdParam
				+ "&agentId=" + agentId + "&spanId=" + spanId;
		System.out.println(s);
		Map spanTrMap = rs.getForObject(s, Map.class);
		sbs = new ArrayList<>();
		for (List strs : (List<List>) spanTrMap.get("callStack")) {
			if (strs.get(10).equals("Tomcat Servlet Process")) {
				sb = new ServicesBean();
				sb.setTgtApp(strs.get(4).toString());
				sb.setTgtRpc(strs.get(4) + ":" + strs.get(11));
				if (sbs.isEmpty()) {
					sb.setSrcApp("USER");
					sb.setSrcRpc("USER");
				} else {
					sb.setSrcApp(sbs.get(sbs.size() - 1).getTgtApp());
					sb.setSrcRpc(sbs.get(sbs.size() - 1).getTgtRpc());
				}
				for (ServicesBean tsb : sbs) {
					if (tsb.getTgtApp().equals(sb.getTgtApp())) {
						sb.setSrcApp(tsb.getSrcApp());
						sb.setSrcRpc(tsb.getSrcRpc());
						break;
					}
				}
				sbs.add(sbs.size(), sb);
				tempK = sb.getServicesRelation();
				if (relaMap.containsKey(tempK)) {
					relaMap.put(tempK, relaMap.get(tempK) + 1L);
				} else {
					relaMap.put(tempK, 1L);
				}
			}
		}
		List<ServiceRelation> resultList = new ArrayList<>();
		String[] temps;
		ServiceRelation sr;
		for (Map.Entry<String, Long> entry : relaMap.entrySet()) {
			temps = entry.getKey().split("\\|\\|");
			sr = new ServiceRelation(temps[0], temps[1], entry.getValue()
					.toString());
			resultList.add(sr);
		}
		return JSON.toJSONString(resultList);
	}

	@RequestMapping(value = "/transactionInfo", method = RequestMethod.GET)
	public String transactionInfo(
			@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "focusTimestamp", required = false, defaultValue = "0") long focusTimestamp,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId,
			@RequestParam(value = "v", required = false, defaultValue = "0") int viewVersion) {
		String s = url + "/transactionInfo.pinpoint?traceId=" + traceIdParam
				+ "&agentId=" + agentId + "&spanId=" + spanId
				+ "&focusTimestamp=" + focusTimestamp;
		System.out.println(s);
		Object model = rs.getForObject(url
				+ "/transactionInfo.pinpoint?traceId=" + traceIdParam
				+ "&agentId=" + agentId + "&spanId=" + spanId
				+ "&focusTimestamp=" + focusTimestamp, Object.class);
		String str = JSON.toJSONString(model);
		return str;
	}

	@RequestMapping(value = "/transactionInfoDetail", method = RequestMethod.GET)
	public String transactionInfoDetail(
			@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "focusTimestamp", required = false, defaultValue = "0") long focusTimestamp,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId,
			@RequestParam(value = "mRpc", required = false, defaultValue = "notFound") String mRpc) {
		String s = url + "/transactionInfo.pinpoint?traceId=" + traceIdParam
				+ "&agentId=" + agentId + "&spanId=" + spanId
				+ "&focusTimestamp=" + focusTimestamp;
		System.out.println(s);
		Map<String, Object> model = rs.getForObject(url
				+ "/transactionInfo.pinpoint?traceId=" + traceIdParam
				+ "&agentId=" + agentId + "&spanId=" + spanId
				+ "&focusTimestamp=" + focusTimestamp, Map.class);
		System.out.println("--------------------------------------------");
		System.out.println(model);
		List<List<Object>> callStack = (List<List<Object>>) model
				.get("callStack");
		if (CollectionUtils.isEmpty(callStack)) {
			return "";
		}
		TreeNode treeNode = recursiveTree(callStack, callStack.get(0).get(6)
				.toString(), mRpc);
		List<TreeNode> rsList = new ArrayList<>();
		rsList.add(treeNode);
		String str = JSON.toJSONString(rsList);
		System.out.println(str);
		return str;
	}

	private TreeNode recursiveTree(List<List<Object>> list, String tid,
			String mRpc) {
		TreeNode tn = new TreeNode();
		List<String> tags = new ArrayList<>();
		List<List<Object>> childList = new ArrayList<>();
		for (List<Object> cList : list) {
			if (tid.equals(cList.get(6).toString())) {
				if (cList.get(4) == null) {
					tn.setTags(null);
					tn.setText(cList.get(10) + "");
					tn.setIcon("glyphicon glyphicon-info-sign");
					continue;
				} else {
					tn.setText(cList.get(10) + " (" + cList.get(11) + ")");
					tags.add(transferLongToDate(sdf, (long) cList.get(1)));
					tags.add(cList.get(14) + "ms");
					tags.add(cList.get(20) + " (" + cList.get(4)
							+ ")");
					tags.add("方法名: " + cList.get(17) + " (" + cList.get(19)
							+ ")");
					tn.setTags(tags);
				}
				if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {
					tn.setIcon("glyphicon glyphicon-cloud");
					if (mRpc.equals(cList.get(11).toString())) {
						tn.setColor("#428bca");
						tn.setBackColor("#9eff7c");
					}
				}
				continue;
			}
			if (tid.equals(cList.get(7).toString())) {
				childList.add(cList);
			}
		}
		for (List<Object> child : childList) {
			TreeNode rl = recursiveTree(list, child.get(6).toString(), mRpc);
			tn.getNodes().add(rl);
		}
		if (CollectionUtils.isEmpty(tn.getNodes())) {
			tn.setNodes(null);
		}
		return tn;
	}

	private String transferLongToDate(SimpleDateFormat sdf, long millSec) {
		Date date = new Date(millSec);
		return sdf.format(date);
	}

}
